package epoch.game.core.http;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.lang.IllegalArgumentException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import epoch.game.core.context.Context;
import epoch.game.core.distr.call.CallReturn;

public class HttpAsyncClient {
	private static final Logger log = LogManager.getLogger(HttpAsyncClient.class);

	private CloseableHttpAsyncClient httpClient = null;

	public HttpAsyncClient(int ioThreads, int connectTimeout, int soTimeout) {
		IOReactorConfig.Builder b = IOReactorConfig.custom();
		b.setConnectTimeout(connectTimeout);
		b.setSoTimeout(soTimeout);
		b.setIoThreadCount(ioThreads);

		httpClient = HttpAsyncClients.custom().setDefaultIOReactorConfig(b.build()).build();
		httpClient.start();
	}

	public void getAsync(String url, Map<String, String> params, CallReturn callRet) {
		try {
			// 默认参数
			if (params == null)
				params = new HashMap<>();

			// 1 拼接地址
			StringBuilder urlSB = new StringBuilder(url);
			// 1.1 有需要拼接的参数
			if (!params.isEmpty()) {
				urlSB.append("?");
			}

			// 1.2 拼接参数
			for (Entry<String, String> entry : params.entrySet()) {
				Object value = entry.getValue();
				String v = (value == null) ? "" : URLEncoder.encode(entry.getValue().toString(), "UTF-8");

				urlSB.append(entry.getKey()).append("=").append(v).append("&");
			}

			if (urlSB.charAt(urlSB.length() - 1) == '&') {
				urlSB.delete(urlSB.length() - 1, urlSB.length());
			}
			// 1.3 最终地址
			String urlStrFinal = urlSB.toString();

			// 请求地址
			HttpGet get = new HttpGet(urlStrFinal);

			httpClient.execute(get, callRet != null ? new Callback(callRet, url, urlStrFinal) : null);
		} catch (Exception e) {
			log.error("httpGetAsync error:", e);
			Context.callRet(callRet, "");
		}
	}

	public void postAsync(String url, Map<String, String> params, CallReturn callRet) {
		try {
			// 默认参数
			if (params == null)
				params = new HashMap<>();

			// 1.2 拼接参数
			List<org.apache.http.NameValuePair> nvps = new java.util.ArrayList<org.apache.http.NameValuePair>();
			for (Entry<String, String> entry : params.entrySet()) {
				Object key = entry.getKey();
				Object val = entry.getValue();
				String valStr = (val == null) ? "" : val.toString();

				nvps.add(new org.apache.http.message.BasicNameValuePair(key.toString(), valStr));
			}

			// 1.3 最终地址
			String urlStrFinal = url;

			// 1.4 去除末尾的&
			if (urlStrFinal.endsWith("&")) {
				urlStrFinal = urlStrFinal.substring(0, urlStrFinal.length() - 1);
			}

			// 请求地址
			HttpPost post = new HttpPost(urlStrFinal);
			post.setEntity(new org.apache.http.client.entity.UrlEncodedFormEntity(nvps, "UTF-8"));

			httpClient.execute(post, callRet != null ? new Callback(callRet, url, urlStrFinal) : null);
		} catch (Exception e) {
			log.error("httpPostAsync error:", e);
			Context.callRet(callRet, "");
		}
	}
	
	public void postAsync(String url, String content, String contentType, CallReturn callRet) {
		try {
			String cType;
			if (contentType == "json") {
				cType = "application/json";
			} else {
				throw new IllegalArgumentException("contentType");
			}
			HttpPost post = new HttpPost(url);
			StringEntity entity = new StringEntity(content, "utf-8");
			entity.setContentEncoding("UTF-8");
			entity.setContentType(cType);
			post.setEntity(entity);

			httpClient.execute(post, callRet != null ? new Callback(callRet, url, content) : null);
		} catch (Exception e) {
			log.error("httpPostAsync error:", e);
			Context.callRet(callRet, "");
		}
	}

	/**
	 * 监听HTTP返回值
	 */
	private static class Callback implements FutureCallback<HttpResponse> {
		private CallReturn callRet;
		private String url;
		private String content;

		public Callback(CallReturn callRet, String url, String content) {
			this.callRet = callRet;
			this.url = url;
			this.content = content;
		}

		@Override
		public void completed(HttpResponse result) {
			try {
				// 返回内容
				HttpEntity entity = result.getEntity();
				// 主体数据
				InputStream in = entity.getContent();
				BufferedReader reader = new BufferedReader(new InputStreamReader(in));
				// 读取
				StringBuilder sb = new StringBuilder();
				String line = null;
				while ((line = reader.readLine()) != null) {
					sb.append(line);
				}
				log.info("http completed:"+sb.toString());
				Context.callRet(callRet, sb.toString());
			} catch (Exception e) {
				log.error("http completed error:", e);
				Context.callRet(callRet, "");
			}
		}

		@Override
		public void failed(Exception ex) {
			log.error("http failed "+url+" "+content);
			Context.callRet(callRet, "");
		}

		@Override
		public void cancelled() {
			log.error("http cancelled "+url+" "+content);
			Context.callRet(callRet, "");
		}
	}
}